home *** CD-ROM | disk | FTP | other *** search
/ Total Network Tools 2002 / NextStepPublishing-TotalNetworkTools2002-Win95.iso / Archive / Misc Servers / Zope.exe / MULTIMAPPING.REF < prev    next >
Encoding:
Text File  |  2000-02-16  |  14.0 KB  |  422 lines

  1. <h1>Example: MultiMapping objects</h1>
  2. <p>  <a href="COPYRIGHT.html">Copyright (C) 1996-1998, Digital Creations</a>.</p>
  3.  
  4. <p>  As an example, consider an extension class that implements a
  5.   "MultiMapping". A multi-mapping is an object that encapsulates 0
  6.   or more mapping objects.  When an attempt is made to lookup an
  7.   object, the encapsulated mapping objects are searched until an
  8.   object is found.</p>
  9.  
  10. <p>  Consider an implementation of a MultiMapping extension type,
  11.   without use of the extension class mechanism:</p>
  12. <PRE>
  13.     #include "Python.h"
  14.  
  15.     #define UNLESS(E) if(!(E))
  16.  
  17.     typedef struct {
  18.         PyObject_HEAD
  19.         PyObject *data;
  20.     } MMobject;
  21.  
  22.     staticforward PyTypeObject MMtype;
  23.  
  24.     static PyObject *
  25.     MM_push(MMobject *self, PyObject *args){
  26.         PyObject *src;
  27.         UNLESS(PyArg_ParseTuple(args, "O", &src)) return NULL;
  28.         UNLESS(-1 != PyList_Append(self->data,src)) return NULL;
  29.         Py_INCREF(Py_None);
  30.         return Py_None;
  31.     }
  32.  
  33.     static PyObject *
  34.     MM_pop(MMobject *self, PyObject *args){
  35.         long l;
  36.         PyObject *r;
  37.         static PyObject *emptyList=0;
  38.  
  39.         UNLESS(emptyList) UNLESS(emptyList=PyList_New(0)) return NULL;
  40.         UNLESS(PyArg_ParseTuple(args, "")) return NULL;
  41.         UNLESS(-1 != (l=PyList_Size(self->data))) return NULL;
  42.         l--;
  43.         UNLESS(r=PySequence_GetItem(self->data,l)) return NULL;
  44.         UNLESS(-1 != PyList_SetSlice(self->data,l,l+1,emptyList)) goto err;
  45.         return r;
  46.     err:
  47.         Py_DECREF(r);
  48.         return NULL;
  49.     }
  50.  
  51.     static struct PyMethodDef MM_methods[] = {
  52.         {"push", (PyCFunction) MM_push, 1,
  53.          "push(mapping_object) -- Add a data source"},
  54.         {"pop",  (PyCFunction) MM_pop,  1,
  55.          "pop() -- Remove and return the last data source added"}, 
  56.         {NULL,              NULL}           /* sentinel */
  57.     };
  58.  
  59.     static PyObject *
  60.     newMMobject(PyObject *ignored, PyObject *args){
  61.         MMobject *self;
  62.  
  63.         UNLESS(PyArg_ParseTuple(args, "")) return NULL;
  64.         UNLESS(self = PyObject_NEW(MMobject, &MMtype)) return NULL;
  65.         UNLESS(self->data=PyList_New(0)) goto err;
  66.         return (PyObject *)self;
  67.     err:
  68.         Py_DECREF(self);
  69.         return NULL;
  70.     }
  71.  
  72.     static void
  73.     MM_dealloc(MMobject *self){
  74.         Py_XDECREF(self->data);
  75.         PyMem_DEL(self);
  76.     }
  77.  
  78.     static PyObject *
  79.     MM_getattr(MMobject *self, char *name){
  80.         return Py_FindMethod(MM_methods, (PyObject *)self, name);
  81.     }
  82.  
  83.     static int
  84.     MM_length(MMobject *self){
  85.         long l=0, el, i;
  86.         PyObject *e=0;
  87.  
  88.         UNLESS(-1 != (i=PyList_Size(self->data))) return -1;
  89.         while(--i >= 0)
  90.           {
  91.             e=PyList_GetItem(self->data,i);
  92.             UNLESS(-1 != (el=PyObject_Length(e))) return -1;
  93.             l+=el;
  94.           }
  95.         return l;
  96.     }
  97.  
  98.     static PyObject *
  99.     MM_subscript(MMobject *self, PyObject *key){
  100.         long i;
  101.         PyObject *e;
  102.  
  103.         UNLESS(-1 != (i=PyList_Size(self->data))) return NULL;
  104.         while(--i >= 0)
  105.           {
  106.             e=PyList_GetItem(self->data,i);
  107.             if(e=PyObject_GetItem(e,key)) return e;
  108.             PyErr_Clear();
  109.           }
  110.         PyErr_SetObject(PyExc_KeyError,key);
  111.         return NULL;
  112.     }
  113.  
  114.     static PyMappingMethods MM_as_mapping = {
  115.               (inquiry)MM_length,           /*mp_length*/
  116.               (binaryfunc)MM_subscript,             /*mp_subscript*/
  117.               (objobjargproc)NULL,          /*mp_ass_subscript*/
  118.     };
  119.  
  120.     /* -------------------------------------------------------- */
  121.  
  122.     static char MMtype__doc__[] = 
  123.     "MultiMapping -- Combine multiple mapping objects for lookup"
  124.     ;
  125.  
  126.     static PyTypeObject MMtype = {
  127.               PyObject_HEAD_INIT(&PyType_Type)
  128.               0,                            /*ob_size*/
  129.               "MultMapping",                        /*tp_name*/
  130.               sizeof(MMobject),             /*tp_basicsize*/
  131.               0,                            /*tp_itemsize*/
  132.               /* methods */
  133.               (destructor)MM_dealloc,               /*tp_dealloc*/
  134.               (printfunc)0,                 /*tp_print*/
  135.               (getattrfunc)MM_getattr,      /*tp_getattr*/
  136.               (setattrfunc)0,                       /*tp_setattr*/
  137.               (cmpfunc)0,                   /*tp_compare*/
  138.               (reprfunc)0,                  /*tp_repr*/
  139.               0,                            /*tp_as_number*/
  140.               0,                            /*tp_as_sequence*/
  141.               &MM_as_mapping,                       /*tp_as_mapping*/
  142.               (hashfunc)0,                  /*tp_hash*/
  143.               (ternaryfunc)0,                       /*tp_call*/
  144.               (reprfunc)0,                  /*tp_str*/
  145.  
  146.               /* Space for future expansion */
  147.               0L,0L,0L,0L,
  148.               MMtype__doc__ /* Documentation string */
  149.     };
  150.  
  151.     static struct PyMethodDef MultiMapping_methods[] = {
  152.         {"MultiMapping", (PyCFunction)newMMobject, 1,
  153.          "MultiMapping() -- Create a new empty multi-mapping"},
  154.         {NULL,              NULL}           /* sentinel */
  155.     };
  156.  
  157.     void
  158.     initMultiMapping(){
  159.         PyObject *m;
  160.  
  161.         m = Py_InitModule4(
  162.             "MultiMapping", MultiMapping_methods,
  163.               "MultiMapping -- Wrap multiple mapping objects for lookup",
  164.               (PyObject*)NULL,PYTHON_API_VERSION);
  165.  
  166.         if (PyErr_Occurred()) 
  167.            Py_FatalError("can't initialize module MultiMapping");
  168.     }
  169.  
  170. </PRE>
  171.  
  172. <p>  This module defines an extension type, <code>MultiMapping</code>, and exports a
  173.   module function, <code>MultiMapping</code>, that creates <code>MultiMapping</code>
  174.   Instances. The type provides two methods, <code>push</code>, and <code>pop</code>, for
  175.   adding and removing mapping objects to the multi-mapping.
  176.   The type provides mapping behavior, implementing mapping length
  177.   and subscript operators but not mapping a subscript assignment
  178.   operator.</p>
  179.  
  180. <p>  Now consider an extension class implementation of MultiMapping
  181.   objects:</p>
  182. <PRE>
  183.     #include "Python.h"
  184.     #include "ExtensionClass.h"
  185.  
  186.     #define UNLESS(E) if(!(E))
  187.  
  188.     typedef struct {
  189.         PyObject_HEAD
  190.         PyObject *data;
  191.     } MMobject;
  192.  
  193.     staticforward PyExtensionClass MMtype;
  194.  
  195.     static PyObject *
  196.     MM_push(self, args)
  197.               MMobject *self;
  198.               PyObject *args;
  199.     {
  200.         PyObject *src;
  201.         UNLESS(PyArg_ParseTuple(args, "O", &src)) return NULL;
  202.         UNLESS(-1 != PyList_Append(self->data,src)) return NULL;
  203.         Py_INCREF(Py_None);
  204.         return Py_None;
  205.     }
  206.  
  207.     static PyObject *
  208.     MM_pop(self, args)
  209.               MMobject *self;
  210.               PyObject *args;
  211.     {
  212.         long l;
  213.         PyObject *r;
  214.         static PyObject *emptyList=0;
  215.  
  216.         UNLESS(emptyList) UNLESS(emptyList=PyList_New(0)) return NULL;
  217.         UNLESS(PyArg_ParseTuple(args, "")) return NULL;
  218.         UNLESS(-1 != (l=PyList_Size(self->data))) return NULL;
  219.         l--;
  220.         UNLESS(r=PySequence_GetItem(self->data,l)) return NULL;
  221.         UNLESS(-1 != PyList_SetSlice(self->data,l,l+1,emptyList)) goto err;
  222.         return r;
  223.     err:
  224.         Py_DECREF(r);
  225.         return NULL;
  226.     }
  227.  
  228.     static PyObject *
  229.     MM__init__(self, args)
  230.            MMobject *self;
  231.            PyObject *args;
  232.     {
  233.         UNLESS(PyArg_ParseTuple(args, "")) return NULL;
  234.         UNLESS(self->data=PyList_New(0)) goto err;
  235.         Py_INCREF(Py_None);
  236.         return Py_None;
  237.     err:
  238.         Py_DECREF(self);
  239.         return NULL;
  240.     }
  241.  
  242.     static struct PyMethodDef MM_methods[] = {
  243.         {"__init__", (PyCFunction)MM__init__, 1,
  244.          "__init__() -- Create a new empty multi-mapping"},
  245.         {"push", (PyCFunction) MM_push, 1,
  246.          "push(mapping_object) -- Add a data source"},
  247.         {"pop",  (PyCFunction) MM_pop,  1,
  248.          "pop() -- Remove and return the last data source added"}, 
  249.         {NULL,              NULL}           /* sentinel */
  250.     };
  251.  
  252.     static void
  253.     MM_dealloc(self)
  254.            MMobject *self;
  255.     {
  256.         Py_XDECREF(self->data);
  257.         PyMem_DEL(self);
  258.     }
  259.  
  260.     static PyObject *
  261.     MM_getattr(self, name)
  262.               MMobject *self;
  263.               char *name;
  264.     {
  265.         return Py_FindMethod(MM_methods, (PyObject *)self, name);
  266.     }
  267.  
  268.     static int
  269.     MM_length(self)
  270.               MMobject *self;
  271.     {
  272.         long l=0, el, i;
  273.         PyObject *e=0;
  274.  
  275.         UNLESS(-1 != (i=PyList_Size(self->data))) return -1;
  276.         while(--i >= 0)
  277.           {
  278.             e=PyList_GetItem(self->data,i);
  279.             UNLESS(-1 != (el=PyObject_Length(e))) return -1;
  280.             l+=el;
  281.           }
  282.         return l;
  283.     }
  284.  
  285.     static PyObject *
  286.     MM_subscript(self, key)
  287.               MMobject *self;
  288.               PyObject *key;
  289.     {
  290.         long i;
  291.         PyObject *e;
  292.  
  293.         UNLESS(-1 != (i=PyList_Size(self->data))) return NULL;
  294.         while(--i >= 0)
  295.           {
  296.             e=PyList_GetItem(self->data,i);
  297.             if(e=PyObject_GetItem(e,key)) return e;
  298.             PyErr_Clear();
  299.           }
  300.         PyErr_SetObject(PyExc_KeyError,key);
  301.         return NULL;
  302.     }
  303.  
  304.     static PyMappingMethods MM_as_mapping = {
  305.               (inquiry)MM_length,           /*mp_length*/
  306.               (binaryfunc)MM_subscript,             /*mp_subscript*/
  307.               (objobjargproc)NULL,          /*mp_ass_subscript*/
  308.     };
  309.  
  310.     /* -------------------------------------------------------- */
  311.  
  312.     static char MMtype__doc__[] = 
  313.     "MultiMapping -- Combine multiple mapping objects for lookup"
  314.     ;
  315.  
  316.     static PyExtensionClass MMtype = {
  317.               PyObject_HEAD_INIT(&PyType_Type)
  318.               0,                            /*ob_size*/
  319.               "MultMapping",                        /*tp_name*/
  320.               sizeof(MMobject),             /*tp_basicsize*/
  321.               0,                            /*tp_itemsize*/
  322.               /* methods */
  323.               (destructor)MM_dealloc,               /*tp_dealloc*/
  324.               (printfunc)0,                 /*tp_print*/
  325.               (getattrfunc)MM_getattr,      /*tp_getattr*/
  326.               (setattrfunc)0,                       /*tp_setattr*/
  327.               (cmpfunc)0,                   /*tp_compare*/
  328.               (reprfunc)0,                  /*tp_repr*/
  329.               0,                            /*tp_as_number*/
  330.               0,                            /*tp_as_sequence*/
  331.               &MM_as_mapping,                       /*tp_as_mapping*/
  332.               (hashfunc)0,                  /*tp_hash*/
  333.               (ternaryfunc)0,                       /*tp_call*/
  334.               (reprfunc)0,                  /*tp_str*/
  335.  
  336.               /* Space for future expansion */
  337.               0L,0L,0L,0L,
  338.               MMtype__doc__, /* Documentation string */
  339.               METHOD_CHAIN(MM_methods)
  340.     };
  341.  
  342.     static struct PyMethodDef MultiMapping_methods[] = {
  343.         {NULL,              NULL}           /* sentinel */
  344.     };
  345.  
  346.     void
  347.     initMultiMapping()
  348.     {
  349.         PyObject *m, *d;
  350.  
  351.         m = Py_InitModule4(
  352.             "MultiMapping", MultiMapping_methods,
  353.             "MultiMapping -- Wrap multiple mapping objects for lookup",
  354.             (PyObject*)NULL,PYTHON_API_VERSION);
  355.         d = PyModule_GetDict(m);
  356.         PyExtensionClass_Export(d,"MultiMapping",MMtype);
  357.  
  358.         if (PyErr_Occurred()) 
  359.            Py_FatalError("can't initialize module MultiMapping");
  360.     }
  361.  
  362. </PRE>
  363.  
  364. <p>  This version includes <code>ExtensionClass.h</code>.  The two declarations of
  365.   <code>MMtype</code> have been changed from <code>PyTypeObject</code> to <code>PyExtensionClass</code>.
  366.   The <code>METHOD_CHAIN</code> macro has been used to add methods to the end of
  367.   the definition for <code>MMtype</code>.  The module function, newMMobject has
  368.   been replaced by the <code>MMtype</code> method, <code>MM__init__</code>.  Note that this
  369.   method does not create or return a new object.  Finally, the lines:</p>
  370. <PRE>
  371.     d = PyModule_GetDict(m);
  372.     PyExtensionClass_Export(d,"MultiMapping",MMtype);
  373.  
  374. </PRE>
  375.  
  376. <p>  Have been added to both initialize the extension class and to export
  377.   it in the module dictionary.</p>
  378.  
  379. <p>  To use this module, compile, link, and import it as with any other
  380.   extension module.  The following python code illustrates the
  381.   module's use:</p>
  382. <PRE>
  383.     from MultiMapping import MultiMapping
  384.     m=MultiMapping()
  385.     m.push({'spam':1, 'eggs':2})
  386.     m.push({'spam':3, 'ham':4})
  387.  
  388.     m['spam'] # returns 3
  389.     m['ham']  # returns 4
  390.     m['foo']  # raises a key error
  391.  
  392. </PRE>
  393.  
  394. <p>  Creating the <code>MultiMapping</code> object took three steps, one to create
  395.   an empty <code>MultiMapping</code>, and two to add mapping objects to it.  We
  396.   might wish to simplify the process of creating MultiMapping
  397.   objects by providing a constructor that takes source mapping
  398.   objects as parameters.  We can do this by sub-classing MultiMapping
  399.   in Python:</p>
  400. <PRE>
  401.     from MultiMapping import MultiMapping
  402.     class ExtendedMultiMapping(MultiMapping):
  403.         def __init__(self,*data):
  404.           MultiMapping.__init__(self)
  405.           for d in data: self.push(d)
  406.  
  407.     m=ExtendedMultiMapping({'spam':1, 'eggs':2}, {'spam':3, 'ham':4})
  408.  
  409.     m['spam'] # returns 3
  410.     m['ham']  # returns 4
  411.     m['foo']  # raises a key error
  412.  
  413. </PRE>
  414.  
  415. <p>  Note that the source file included in the ExtensionClass
  416.   distribution has numerous enhancements beyond the version shown in
  417.   this document.
  418. </p>
  419.  
  420.  
  421.  
  422.